home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Developer Toolbox 6.1
/
SGI Developer Toolbox 6.1 - Disc 4.iso
/
src
/
demos
/
REALITY
/
distort
/
ripple.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-01
|
5KB
|
236 lines
/*
* Copyright 1993, 1994, Silicon Graphics, Inc.
* All Rights Reserved.
*
* This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
* the contents of this file may not be disclosed to third parties, copied or
* duplicated in any form, in whole or in part, without the prior written
* permission of Silicon Graphics, Inc.
*
* RESTRICTED RIGHTS LEGEND:
* Use, duplication or disclosure by the Government is subject to restrictions
* as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
* and Computer Software clause at DFARS 252.227-7013, and/or in similar or
* successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
* rights reserved under the Copyright Laws of the United States.
*/
/*
ripple.c
Drew Olbrich, 1992
This distortion effect approximates looking down at an
image through a layer of water. The user can poke
at the water using the mouse, generating one or more
ripple patterns.
To create the effect, an large texture image is mapped
onto a mesh of polygons. Only the texture coordinates of
the polygon vertices are distorted -- not the vertex
coordinates.
*/
#include <stdio.h>
#include <math.h>
#include <gl.h>
#include <device.h>
#include "defs.h"
#include "ripple.h"
EFFECT ripple = { ripple_init, ripple_dynamics, ripple_redraw, ripple_click };
static RIPPLE_VERTEX ripple_vertex[GRID_SIZE_X][GRID_SIZE_Y];
static int cx[RIPPLE_COUNT];
static int cy[RIPPLE_COUNT];
static int t[RIPPLE_COUNT];
static int max[RIPPLE_COUNT];
static int ripple_max;
/*
Initialize ripple location and age information.
Also, precompute the vertex coordinates and the default texture
coordinates assigned to them.
*/
void ripple_init()
{
int i, j;
zbuffer(FALSE);
ripple_max = (int) sqrt(WIN_SIZE_X*WIN_SIZE_X + WIN_SIZE_Y*WIN_SIZE_Y);
for (i = 0; i < RIPPLE_COUNT; i++)
{
t[i] = ripple_max + RIPPLE_LENGTH;
cx[i] = 0;
cy[i] = 0;
max[i] = 0;
}
for (i = 0; i < GRID_SIZE_X; i++)
for (j = 0; j < GRID_SIZE_Y; j++)
{
ripple_vertex[i][j].x[0] = i/(GRID_SIZE_X - 1.0)*WIN_SIZE_X;
ripple_vertex[i][j].x[1] = j/(GRID_SIZE_Y - 1.0)*WIN_SIZE_Y;
ripple_vertex[i][j].dt[0] = i/(GRID_SIZE_X - 1.0);
ripple_vertex[i][j].dt[1] = j/(GRID_SIZE_Y - 1.0);
}
}
/*
Advance one time step and compute new texture coordinates
for the next frame of animation.
*/
void ripple_dynamics(int mousex, int mousey)
{
int i, j, k;
int x, y;
int mi, mj;
int r;
float sx, sy;
float amp;
for (i = 0; i < RIPPLE_COUNT; i++)
t[i] += RIPPLE_STEP;
for (i = 0; i < GRID_SIZE_X; i++)
for (j = 0; j < GRID_SIZE_Y; j++)
{
ripple_vertex[i][j].t[0] = ripple_vertex[i][j].dt[0];
ripple_vertex[i][j].t[1] = ripple_vertex[i][j].dt[1];
for (k = 0; k < RIPPLE_COUNT; k++)
{
x = i - cx[k];
y = j - cy[k];
if (x < 0)
{
x *= -1;
sx = -1.0;
}
else
sx = 1.0;
if (y < 0)
{
y *= -1;
sy = -1.0;
}
else
sy = 1.0;
mi = x;
mj = y;
r = t[k] - ripple_vector[mi][mj].r;
if (r < 0)
r = 0;
if (r > RIPPLE_LENGTH - 1)
r = RIPPLE_LENGTH - 1;
amp = 1.0 - 1.0*t[k]/RIPPLE_LENGTH;
amp *= amp;
if (amp < 0.0)
amp = 0.0;
ripple_vertex[i][j].t[0]
+= ripple_vector[mi][mj].dx[0]*sx*ripple_amp[r].amplitude*amp;
ripple_vertex[i][j].t[1]
+= ripple_vector[mi][mj].dx[1]*sy*ripple_amp[r].amplitude*amp;
}
}
}
/*
Draw the next frame of animation.
*/
void ripple_redraw()
{
int i, j;
cpack(0xFFFFFFFF);
for (i = 0; i < GRID_SIZE_X - 1; i++)
{
for (j = 0; j < GRID_SIZE_Y - 1; j++)
{
bgnpolygon();
t2f(ripple_vertex[i][j].t);
v2f(ripple_vertex[i][j].x);
t2f(ripple_vertex[i][j + 1].t);
v2f(ripple_vertex[i][j + 1].x);
t2f(ripple_vertex[i + 1][j + 1].t);
v2f(ripple_vertex[i + 1][j + 1].x);
t2f(ripple_vertex[i + 1][j].t);
v2f(ripple_vertex[i + 1][j].x);
endpolygon();
}
}
swapbuffers();
}
/*
Calculate the distance between two points.
*/
float ripple_distance(int gx, int gy, int cx, int cy)
{
return sqrt(1.0*(gx - cx)*(gx - cx) + 1.0*(gy - cy)*(gy - cy));
}
/*
Compute the distance of the given window coordinate
to the nearest window corner, in pixels.
*/
int ripple_max_distance(int gx, int gy)
{
float d;
float temp_d;
d = ripple_distance(gx, gy, 0, 0);
temp_d = ripple_distance(gx, gy, GRID_SIZE_X, 0);
if (temp_d > d)
d = temp_d;
temp_d = ripple_distance(gx, gy, GRID_SIZE_X, GRID_SIZE_Y);
if (temp_d > d)
d = temp_d;
temp_d = ripple_distance(gx, gy, 0, GRID_SIZE_Y);
if (temp_d > d)
d = temp_d;
return (d/GRID_SIZE_X)*WIN_SIZE_X + RIPPLE_LENGTH/6;
}
/*
Generate a new ripple when the mouse is pressed. There's
a limit on the number of ripples that can be simultaneously
generated.
*/
void ripple_click(int mousex, int mousey, int state)
{
int index;
if (state)
{
index = 0;
while (t[index] < max[index] && index < RIPPLE_COUNT)
index++;
if (index < RIPPLE_COUNT)
{
cx[index] = 1.0*mousex/WIN_SIZE_X*GRID_SIZE_X;
cy[index] = 1.0*mousey/WIN_SIZE_Y*GRID_SIZE_Y;
t[index] = 4*RIPPLE_STEP;
max[index] = ripple_max_distance(cx[index], cy[index]);
}
}
}